
#include <BFont>
#include <BPainter>
#include <BMouseEvent>
#include <BKeyEvent>
#include <BScrollBar>
#include <BStyle>

#include "member_BObject.h"
#include "member_BComboBox.h"
#include "member_BComboItem.h"

using namespace BWE;

member_BComboBox::member_BComboBox(BComboBox* comboBox)
{
	boss = comboBox;
	alignment.ia_align = Align_LeftCenter;
	current = 0;
	editable = false;
	readOnly = false;
	blinkTime = 1;
	blinkTick = 0;
	blinkShown = false;
	popupOnClick = true;

	dirty = true;
	editing = false;
	pressed = false;
	hoverIndex = 0;

	arrow = new BButton(Graph_Arrow_Down_Fill);
	arrow->setName("arrow");
	arrow->setCheckable(true);
	arrow->setEnabled(false);
	boss->addChild(arrow);

	board = new IComboBoard(&items, boss);
	board->setName("board");

	connect(arrow, Signal_Checked, &member_BComboBox::slotArrowChecked);
	connect(board, Signal_Clicked, &member_BComboBox::slotBoardClicked);
	connect(board, Signal_Styled, &member_BComboBox::slotBoardStyled);

}
member_BComboBox::~member_BComboBox()
{

}

void member_BComboBox::emitEdited()
{
	editing = true;
	dirty = true;
	if (boss->checks(Signal_TextEdited))
		boss->emit(Signal_TextEdited, block.text);
	if (boss->checks(Signal_TextChanged))
		boss->emit(Signal_TextChanged, block.text);
	if (current)
	{
		current = 0;
		value.clear();
		boss->emit(Signal_CurrentChanged, BValue());
	}
	boss->fresh();
}

bool member_BComboBox::imageShown()
{
	if (alignment.ia_form > Form_IconAlone)
		return true;
	bool hasIcon = false;
	for (int i = 0; i < items.size(); i++)
	{
		BComboItem* item = items[i];
		if (item_member(item)->graph || item_member(item)->image || item_member(item)->icon)
		{
			hasIcon = true;
			break;
		}
	}
	if (alignment.ia_form == Form_IconAlone)
	{
		if (!hasIcon)
			return false;
		return true;
	}
	if (alignment.ia_form == Form_TextAlone)
	{
		if (block.text.empty() && hasIcon)
			return true;
		return false;
	}
	return hasIcon;
}
void member_BComboBox::freshRects()
{
	const BStyle* style = boss->realStyle();
	const BFont* font = boss->realFont();
	BRect crect = boss->centerRect();

	arrow->setParent(boss);
	arrow->setEnabled(!readOnly);
	if (arrow->visible())
	{
		int arrowWidth = arrow->sizeHint().width();
		if (boss->perch().right() < arrowWidth)
			boss->setPerch(Part_Right, arrowWidth);
		BRect rightRect = boss->rect(Part_Right);
		arrow->setSize(rightRect.size());
		BRect arrowRect = rightRect.align(Align_Center, arrow->size());
		arrow->setRect(arrowRect);
	}

	BSize realIconSize = iconSize;
	if (imageShown())
	{
		if (realIconSize.width() == 0)
			realIconSize.width() = font->size();
		if (realIconSize.height() == 0)
			realIconSize.height() = font->size();
	}

	if (!editing && current)
	{
		block.text = item_member(current)->block.text;
		block.reset();
	}
	block.font = font;
	block.dirty = true;
	block.adjust(0);
	if (block.empty() && editable)
		block.textSize.width() = 1;

	alignment.ia_iconSize = realIconSize;
	alignment.ia_textSize = block.textSize;
	alignment.adjust(crect);

	block.rect = alignment.ia_textRect;
}
BLine2 member_BComboBox::inputLine()
{
	BLine2 line;
	if (block.cells.check(block.index))
	{
		BRect cellRect = block.cells[block.index].rect + block.rect.pos();
		line.setBegin(cellRect.left() + 1, block.rect.top());
		line.setEnd(cellRect.left() + 1, block.rect.bottom());

	}
	else
	{
		BRect cellRect = block.cells.last().rect + block.rect.pos();
		line.setBegin(cellRect.right() + 1, block.rect.top());
		line.setEnd(cellRect.right() + 1, block.rect.bottom());
	}
	if (!alignment.ia_textArea.contain(line.begin()))
	{
		BPoint point = alignment.ia_textArea.wrap(line.begin());
		BPoint offset = point - line.begin();
		block.rect.move(offset.x(), 0);
		line.move(offset.x(), 0);
	}
	return line;
}

void member_BComboBox::slotArrowChecked(BObject* object, const BValue& value)
{
	board->setParent(boss);
	if (arrow->checked())
		board->popup();
	else
		board->hide();
	if (board->visible())
	{
		BRect hostRect = boss->rect();
		BRect rootRect = boss->mapFrom(boss->root(), boss->root()->size());
		BPoint offset = board->popupOffset;
		BSize size = board->sizeHint();
		if (size.width() < hostRect.width())
			size.width() = hostRect.width();
		if (size.width() > rootRect.width())
			size.width() = rootRect.width();
		int spaceUp = -rootRect.top();
		int spaceDown = rootRect.bottom() - hostRect.height();
		if (spaceDown < size.height() && spaceDown < spaceUp)
		{
			size.height() = bMin(size.height(), spaceUp);
			board->setSize(size);
			board->setPos(offset.x(), offset.y() - board->height());
		}
		else
		{
			size.height() = bMin(size.height(), spaceDown);
			board->setSize(size);
			board->setPos(offset.x(), offset.y() + hostRect.height());
		}
		boss->emit(Signal_Popup, board);
	}
}
void member_BComboBox::slotBoardClicked(BObject* object, const BValue& value)
{
	arrow->setChecked(false);
}
void member_BComboBox::slotBoardStyled(BObject* object, const BValue& value)
{
	dirty = true;
	boss->fresh();
}

void member_BComboBox::slotItemColorChanged(BObject* object, const BValue& vaue)
{
	board->fresh();
	dirty = true;
	if (current == object)
	{
		object_member(boss)->emit(Signal_ColorChanged, value);
	}
	boss->fresh();
}
void member_BComboBox::slotItemGraphChanged(BObject* object, const BValue& vaue)
{
	board->dirty = true;
	board->fresh();
	dirty = true;
	if (current == object)
	{
		object_member(boss)->emit(Signal_GraphChanged, value);
	}
	boss->fresh();
}
void member_BComboBox::slotItemImageChanged(BObject* object, const BValue& vaue)
{
	board->dirty = true;
	board->fresh();
	dirty = true;
	if (current == object)
	{
		object_member(boss)->emit(Signal_ImageChanged, value);
	}
	boss->fresh();
}
void member_BComboBox::slotItemIconChanged(BObject* object, const BValue& value)
{
	board->dirty = true;
	board->fresh();
	dirty = true;
	if (current == object)
	{
		object_member(boss)->emit(Signal_IconChanged, value);
	}
	boss->fresh();
}
void member_BComboBox::slotItemValueChanged(BObject* object, const BValue& value)
{
	if (current == object)
	{
		this->value = value;
		if (boss->checks(Signal_ValueChanged))
			boss->emit(Signal_ValueChanged, value);
	}
}
void member_BComboBox::slotItemTextChanged(BObject* object, const BValue& value)
{
	if (!editing)
	{
		block.clear();
	}
	board->dirty = true;
	board->fresh();
	dirty = true;
	if (boss->checks(Signal_TextChanged))
		boss->emit(Signal_TextChanged, value);
	boss->fresh();
}
